home *** CD-ROM | disk | FTP | other *** search
- ; DO_REC.ASM
- ;
- ; External assembler subroutine for Recwav.pas, performs the actual record-
- ; ing of sound. Although this is to be assembled to an .obj file, it is
- ; almost a .com file in its own right. This routine assumes the DAC has
- ; already been initialized.
- ;
-
- CODE SEGMENT BYTE PUBLIC
- ASSUME CS:CODE,DS:CODE
- PUBLIC DO_REC
- DO_REC PROC NEAR
- JMP START
- ;
- ; Stack frame structure.
- ;
- STACKFRAME STRUC [BP]
- OLDBP DW ? ; caller's BP
- RETADDR DW ? ; return address
- ASCZFILE DD ? ; pointer to ASCIIZ filename of output file
- BUFFER1 DD ? ; pointer to DMA buffer 1
- BUFFER0 DD ? ; pointer to DMA buffer 0
- INRATE DW ? ; input sampling rate in Hz, for .wav header
- DIVIDER DW ? ; divider for Int 1Ah function 82h
- ENDS
- ;
- ; Return codes.
- ;
- RECOK EQU 0 ; recording successful
- DISKERR EQU 1 ; disk I/O error
- FULLDISK EQU 2 ; disk full
- OVERFLOW EQU 3 ; input overflow (sampling rate too fast)
- OPENFAIL EQU 4 ; open failed on output file
- WORKING EQU 5 ; sound input in progress (not a return code)
- ;
- ; Local data. First, copies of parameters (easier to get at,
- ; particularly from inside an interrupt handler).
- ;
- ASCZFILE_L DD 0 ; local copy of parameter ASCZFILE
- BUFFERPTRS LABEL DWORD ; buffer pointers, as array[0..1] of dword
- BUFFER0_L DD 0 ; local copy of parameter BUFFER0
- BUFFER1_L DD 0 ; local copy of parameter BUFFER1
- DIVIDER_L DW 0 ; local copy of parameter DIVIDER
- EVENT DW WORKING ; event status (return code)
- CURRENTOUT DW 0 ; current output buffer (0 or 1)
- CURRENTIN DW 0 ; current input buffer (0 or 1)
- FULLBUFFER DB 0,0 ; buffer full flags, 1 = full
- LASTBUFFER DB 0,0 ; last buffer flags, 1 = final buffer
- STOPNOW DB 0 ; 1 = recording should stop
- RECSTOPPED DB 0 ; 1 = sound recording stopped
- KEYPRESSED DB 0 ; key pressed flag, 1 = key has been pressed
- HANDLE DW 0 ; file handle of output file
- FILELEN DD 0 ; length of the output file
- STARTPROMPT DB "Press a key to begin recording.",0Dh,0Ah,"$"
- STOPPROMPT DB "Press a key to stop recording.",0Dh,0Ah,"$"
- INT15VEC DD 0 ; default Int 15h vector
- ;
- ; RIFF WAVE header template, for writing to the output file.
- ; 44 bytes long. OUTRATE1 and OUTRATE2 should be filled in
- ; before the template is written out. After recording is
- ; done, the dword at offset 4 should be filled in with the
- ; length of the output file minus 8, and the dword at offset
- ; 40 should be filled in with the length of the output file
- ; minus 44.
- ;
- TEMPLATE LABEL BYTE
- DB 'RIFF' ; RIFF header
- RIFFSIZE DD 0 ; (length of output file) - 8 goes here
- DB 'WAVEfmt ' ; WAVE header and format chunk label
- DD 16 ; format chunk length
- DW 1 ; Microsoft PCM format tag
- DW 1 ; mono
- OUTRATE1 DW 0 ; fill in with sampling rate
- DW 0
- OUTRATE2 DW 0 ; fill in sampling rate here too
- DW 0
- DW 1 ; bytes per sample
- DW 8 ; bits per sample
- DB 'data'
- DATASIZE DD 0 ; (length of output file) - 44 goes here
- ;
- ; Replacement Int 15h handler. This is actually 2 Int 15h
- ; handlers in one: the first part handles Int 15h function
- ; 4Fh, the keyboard intercept, setting the KEYPRESSED flag
- ; above and telling the BIOS to ignore the keystroke; the
- ; second part handles Int 15h, AX=91FBh, the BIOS callout
- ; for sound chip DMA EOP.
- ;
- ; First part: keyboard intercept. Set KEYPRESSED flag (if
- ; it's a make code) and tell the BIOS to ignore the keystroke.
- ;
- INT15HDLR: CMP AH,4Fh
- JNE I15_NOTKEY
- NOT AL ; 1 in bit 7 = make code
- ROL AL,1 ; 1 in bit 0 = make code
- AND AL,1 ; zero out other bits
- OR CS:KEYPRESSED,AL ; set if make code
- CLC
- RETF 2
- ;
- ; If not keyboard intercept, and not DMA EOP, then jump to
- ; default handler.
- ;
- I15_NOTKEY: CMP AX,91FBh
- JE I15_DMAEOP
- JMP DWORD PTR CS:INT15VEC
- ;
- ; DMA end-of-process occurred on sound input. DS addresses
- ; local data.
- ;
- I15_DMAEOP: PUSH AX
- PUSH BX
- PUSH CX
- PUSH DX
- PUSH DS
- PUSH ES
- PUSH CS
- POP DS
- ;
- ; Check first if STOPNOW flag is set; if so, stop. (The main
- ; program sets this flag in case of disk errors.)
- ;
- CMP STOPNOW,1
- JNE NOTSTOPNOW
- MOV RECSTOPPED,1
- JMP I15_END
- ;
- ; STOPNOW flag not set. Mark the current buffer full. If a
- ; keystroke has occurred, mark the current buffer last and
- ; stop.
- ;
- NOTSTOPNOW: MOV BX,CURRENTIN
- MOV FULLBUFFER[BX],1
- CMP KEYPRESSED,1
- JNE NOKEYYET
- MOV RECSTOPPED,1
- MOV LASTBUFFER[BX],1
- JMP I15_END
- ;
- ; No keypress yet. Switch input buffers.
- ;
- NOKEYYET: XOR BX,1
- MOV CURRENTIN,BX
- ;
- ; If the new current input buffer is still marked full,
- ; overflow has occurred.
- ;
- CMP FULLBUFFER[BX],1
- JNE NOOVERFLOW
- MOV RECSTOPPED,1
- MOV EVENT,OVERFLOW
- JMP I15_END
- ;
- ; Buffer is empty. Fill it.
- ;
- NOOVERFLOW: MOV AH,82h
- SHL BX,1
- SHL BX,1
- LES BX,BUFFERPTRS[BX]
- MOV CX,32768
- MOV DX,DIVIDER_L
- INT 1Ah
- I15_END: POP ES
- POP DS
- POP DX
- POP CX
- POP BX
- POP AX
- IRET
- ;
- ; Subroutine, opens the output file. Returns: carry set if
- ; error, file handle in AX otherwise.
- ;
- OPENFILE: PUSH CX
- PUSH DX
- PUSH DS
- MOV AH,3Ch
- XOR CX,CX
- LDS DX,ASCZFILE_L
- INT 21h
- POP DS
- POP DX
- POP CX
- RET
- ;
- ; Subroutine, closes the output file and flushes the disk
- ; buffers. Returns nothing.
- ;
- CLOSEFILE: PUSH AX
- PUSH BX
- MOV AH,3Eh
- MOV BX,HANDLE
- INT 21h
- MOV AH,0Dh
- INT 21h
- POP BX
- POP AX
- RET
- ;
- ; Subroutine, erases the output file.
- ;
- ERASEFILE: PUSH AX
- PUSH DX
- PUSH DS
- MOV AH,41h
- LDS DX,ASCZFILE_L
- INT 21h
- POP DS
- POP DX
- POP AX
- RET
- ;
- ; Subroutine, starts sound recording.
- ;
- STARTRECORD: PUSH AX
- PUSH BX
- PUSH CX
- PUSH DX
- PUSH ES
- MOV AH,82h
- LES BX,BUFFER0_L
- MOV CX,32768
- MOV DX,DIVIDER_L
- INT 1Ah
- POP ES
- POP DX
- POP CX
- POP BX
- POP AX
- RET
- ;
- ; Subroutine, stops sound recording. Waits for the recording
- ; process to indicate that it has stopped.
- ;
- STOPRECORD: MOV STOPNOW,1
- L0: CMP RECSTOPPED,1
- JNE L0
- RET
- ;
- ; Main routine. BP addresses the stack frame; DS addresses
- ; the code segment.
- ;
- START: PUSH BP
- MOV BP,SP
- PUSH DS
- PUSH CS
- POP DS
- ;
- ; Create local copies of parameters.
- ;
- MOV AX,DIVIDER
- MOV DIVIDER_L,AX
- MOV AX,INRATE ; fill in header template
- MOV OUTRATE1,AX
- MOV OUTRATE2,AX
- LES AX,BUFFER0
- MOV WORD PTR BUFFER0_L,AX
- MOV WORD PTR BUFFER0_L+2,ES
- LES AX,BUFFER1
- MOV WORD PTR BUFFER1_L,AX
- MOV WORD PTR BUFFER1_L+2,ES
- LES AX,ASCZFILE
- MOV WORD PTR ASCZFILE_L,AX
- MOV WORD PTR ASCZFILE_L+2,ES
- ;
- ; Open the output file.
- ;
- CALL OPENFILE
- JNC OPEN_SUCCESS
- ;
- ; Open failed. Set event code and jump to end.
- ;
- MOV EVENT,OPENFAIL
- JMP MAIN_EXIT
- ;
- ; Open succeeded. Save handle and write .wav header.
- ;
- OPEN_SUCCESS: MOV HANDLE,AX
- MOV BX,AX
- MOV AH,40h
- MOV CX,44
- MOV DX,OFFSET TEMPLATE
- INT 21h
- JC HDR_FAIL
- CMP AX,CX
- JE HDR_SUCCESS
- ;
- ; Error writing to disk. Close the output file and delete it,
- ; set event code to DISKERR, and jump to exit.
- ;
- HDR_FAIL: CALL CLOSEFILE
- CALL ERASEFILE
- MOV EVENT,DISKERR
- JMP MAIN_EXIT
- ;
- ; Header successfully written out. Display starting prompt
- ; to the user.
- ;
- HDR_SUCCESS: MOV AH,9
- MOV DX,OFFSET STARTPROMPT
- INT 21h
- ;
- ; Flush the keyboard buffer.
- ;
- KEYBUF_FLUSH: MOV AH,1
- INT 16h
- JZ KEYBUF_EMPTY
- MOV AH,0
- INT 16h
- JMP KEYBUF_FLUSH
- ;
- ; Keyboard buffer empty. Wait for a keystroke.
- ;
- KEYBUF_EMPTY: MOV AH,0
- INT 16h
- ;
- ; Display stopping prompt to the user.
- ;
- MOV AH,9
- MOV DX,OFFSET STOPPROMPT
- INT 21h
- ;
- ; Hook Int 15h.
- ;
- MOV AX,3515h
- INT 21h
- MOV WORD PTR INT15VEC,BX
- MOV WORD PTR INT15VEC+2,ES
- MOV AX,2515h
- MOV DX,OFFSET INT15HDLR
- INT 21h
- ;
- ; Start recording.
- ;
- CALL STARTRECORD
- ;
- ; **** Main output loop. If overflow has occurred, close
- ; and delete the output file and exit the program.
- ;
- MAINLOOP: CMP EVENT,OVERFLOW
- JNE NO_OVERFLOW
- CALL CLOSEFILE
- CALL ERASEFILE
- JMP UNHOOK
- ;
- ; No overflow. See if the current output buffer is full yet.
- ; If not, keep checking for overflow or a full buffer.
- ;
- NO_OVERFLOW: MOV SI,CURRENTOUT
- CMP FULLBUFFER[SI],1
- JNE MAINLOOP
- ;
- ; Write the buffer to disk.
- ;
- PUSH DS
- MOV AH,40h
- MOV BX,HANDLE
- MOV CX,32768
- SHL SI,1
- SHL SI,1
- LDS DX,BUFFERPTRS[SI]
- INT 21h
- POP DS
- ;
- ; If disk error, stop recording, close and delete the output
- ; file, set the return code to DISKERR, and exit.
- ;
- JNC BUFFERDONE
- CALL STOPRECORD
- CALL CLOSEFILE
- CALL ERASEFILE
- MOV EVENT,DISKERR
- JMP UNHOOK
- ;
- ; If full disk, stop recording, set return code to FULLDISK,
- ; and go set the file size in the .wav header.
- ;
- BUFFERDONE: CMP AX,CX
- JE NOTFULL
- CALL STOPRECORD
- MOV EVENT,FULLDISK
- JMP SETSIZE
- ;
- ; Disk not full. If this was the last output buffer, exit
- ; the loop (recording already stopped).
- ;
- NOTFULL: MOV BX,CURRENTOUT
- CMP LASTBUFFER[BX],1
- JE MAIN_LPEND
- ;
- ; Not the last output buffer. Mark the current output buffer
- ; empty, switch buffers, and go to the top of the loop to wait
- ; for more output.
- ;
- MOV FULLBUFFER[BX],0
- XOR CURRENTOUT,1
- JMP MAINLOOP
- ;
- ; Recording successful.
- ;
- MAIN_LPEND: MOV EVENT,RECOK
- ;
- ; Set the size fields in the .wav header. First, get the
- ; length of the file from DOS.
- ;
- SETSIZE: MOV AX,4202h
- MOV BX,HANDLE
- XOR CX,CX
- MOV DX,CX
- INT 21h
- JC SIZEERROR
- ;
- ; Fill in the size fields in the .wav header template.
- ;
- SUB AX,8
- SBB DX,0
- MOV WORD PTR RIFFSIZE,AX
- MOV WORD PTR RIFFSIZE+2,DX
- SUB AX,36
- SBB DX,0
- MOV WORD PTR DATASIZE,AX
- MOV WORD PTR DATASIZE+2,DX
- ;
- ; Seek to the beginning of the file and write out the header
- ; template again.
- ;
- MOV AX,4200h
- MOV BX,HANDLE
- XOR CX,CX
- MOV DX,CX
- INT 21h
- JC SIZEERROR
- MOV AH,40h
- MOV BX,HANDLE
- MOV CX,44
- MOV DX,OFFSET TEMPLATE
- INT 21h
- JC SIZEERROR
- CMP AX,CX
- JNE SIZEERROR
- ;
- ; Close the output file and exit.
- ;
- CALL CLOSEFILE
- JMP UNHOOK
- ;
- ; File error occurred while setting the size fields in the
- ; .wav header, or when closing the file. Close the file
- ; (if not closed already) and delete it, then set the return
- ; code to DISKERR.
- ;
- SIZEERROR: CALL CLOSEFILE
- CALL ERASEFILE
- MOV EVENT,DISKERR
- ;
- ; Unhook Int 15h.
- ;
- UNHOOK: PUSH DS
- MOV AX,2515h
- LDS DX,INT15VEC
- INT 21h
- POP DS
- ;
- ; Set return code, restore registers and exit.
- ;
- MAIN_EXIT: MOV AX,EVENT
- POP DS
- POP BP
- RET 16 ; discard parameters
- DO_REC ENDP
- CODE ENDS
- END